<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * This file contains the UserAgent class.
 *
 * PHP version 5
 *
 * This file is part of Majic - A rapid-development web application framework
 * for PHP 5.
 *
 * Majic is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * Majic is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Majic. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package     UserAgent
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 * @copyright   2007-2008 Michael J. I. Jackson
 * @license     http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL 3.0
 * @version     SVN: $Id: UserAgent.php 34 2008-07-19 04:50:53Z mjijackson $
 */

use_helper('string'); // for validate_ip()

/**
 * Class for retrieving information about the application user agent (client).
 *
 * @package     UserAgent
 * @author      Michael J. I. Jackson <mjackson@omniture.com>
 */
class UserAgent
{

    /**
     * An array containing the languages this client will accept.
     *
     * @var     array
     * @access  private
     * @static
     */
    private static $languages;

    /**
     * An array containing the character sets this client will accept.
     *
     * @var     array
     * @access  private
     * @static
     */
    private static $charsets;

    /**
     * Gets the client's IP address. Will return 'unknown' if the address
     * cannot be determined or 'invalid' if it is not a valid IP address.
     *
     * @return  string          The client's IP address
     * @access  public
     * @static
     */
    public static function getIP()
    {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (!empty($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        } else {
            $ip = 'unknown';
        }

        if (strstr($ip, ',')) {
            $x = explode(',', $ip);
            $ip = end($x);
        }

        if ($ip != 'unknown' && !validate_ip($ip)) {
            $ip = 'invalid';
        }

        return $ip;
    }

    /**
     * Gets the HTTP_USER_AGENT string..
     *
     * @return  string      The client's HTTP_USER_AGENT string
     * @access  public
     * @static
     */
    public static function getUserAgent()
    {
        return getenv('HTTP_USER_AGENT');
    }

    /**
     * Gets the HTTP_REFERER string.
     *
     * @return  string      The HTTP_REFERER string
     * @access  public
     * @static
     */
    public static function getReferer()
    {
        return getenv('HTTP_REFERER');
    }

    /**
     * Gets an array of languages accepted by the client.
     *
     * @return  array       The accepted languages
     * @access  public
     * @static
     */
    public static function getLanguages()
    {
        if (!isset(self::$languages)) {
            $httplanguages = getenv('HTTP_ACCEPT_LANGUAGE');

            $langs = array();
            if (!empty($httplanguages)) {
                $accepted = preg_split('/,\s*/', $httplanguages);

                foreach ($accepted as $accept) {
                    $result = preg_match('/^([a-z]{1,8}(?:[-_][a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i',
                                         $accept, $match);
                    if (!$result) {
                        continue;
                    }

                    $q = isset($match[2]) ? (float) $match[2] : 1.0;

                    $countrys = explode('-', $match[1]);
                    $region = array_shift($countrys);

                    $country2 = explode('_', $region);
                    $region = array_shift($country2);

                    foreach($countrys as $country) {
                        $langs[$region . '_' . strtoupper($country)] = $q;
                    }
                    foreach($country2 as $country) {
                        $langs[$region . '_' . strtoupper($country)] = $q;
                    }
                    if (!isset($langs[$region]) || ($langs[$region] < $q)) {
                        $langs[$region] = $q;
                    }
                }
            }

            self::$languages = $langs;
        }

        return self::$languages;
    }

    /**
     * Determines if the given language is accepted by the client.
     *
     * <code>
     * $en = UserAgent::acceptsLang('en');
     * </code>
     *
     * @param   string      $lang       The language to check
     * @return  bool                    True if the user agent accepts the given
     *                                  language, false otherwise
     * @access  public
     * @static
     */
    public static function acceptsLang($lang)
    {
        $langs = self::getLanguages();
        return isset($langs[$lang]) && $langs[$lang] != 0;
    }

    /**
     * Gets an array of character sets accepted by the client.
     *
     * @return  array       The accepted character sets
     * @access  public
     * @static
     */
    public static function getCharsets()
    {
        if (!isset(self::$charsets)) {
            $httpcharsets = getenv('HTTP_ACCEPT_CHARSET');

            $charsets = array();
            if ($httpcharsets !== false) {
                $accepted = preg_split('/,\s*/', $httpcharsets);
                foreach ($accepted as $accept) {
                    if (empty($accept)) {
                        continue;
                    }

                    if (strpos($accept, ';')) {
                        $q = (float) substr($accept, strpos($accept, '=') + 1);
                        $accept = substr($accept, 0, strpos($accept, ';'));
                    } else {
                        $q = 1.0;
                    }

                    $charsets[strtolower($accept)] = $q;
                }
            }

            self::$charsets = $charsets;
        }

        return self::$charsets;
    }

    /**
     * Determines if the given character set is accepted by the client.
     *
     * <code>
     * $utf8 = UserAgent::acceptsCharset('utf-8');
     * </code>
     *
     * @param   string      $charset    The character set to check
     * @return  bool                    True if the user agent accepts the given
     *                                  character set, false otherwise
     * @access  public
     * @static
     */
    public static function acceptsCharset($charset)
    {
        $charsets = self::getCharsets();
        $charset = strtolower($charset);
        return isset($charsets[$charset]) && $charsets[$charset] != 0;
    }

}

?>
